﻿/*
 * Copyright (c) HiSilicon (Shanghai) Technologies Co., Ltd. 2023-2023. All rights reserved.
 */

#include "MultipleBurnDlg.h"
#include <QSettings>
#include <QMessageBox>
#include <QFileDialog>
#include <QTimer>
#include "BurnToolCommon/Global.h"

namespace BurnDlg {

namespace  {
    const int CHECK_COM_TIME = 200; // 200ms
    const int NUM_ONE_HUNDRED = 100;
    const int TIMER_CONSUMED_INTERVAL = 200;
    const int SLEEP_TIME_OUT = 100;
    const int WAIT_TIME_OUT = 200;
    const int XNUM_VALUE = 10;
    const int PERIOD_VALUE = 10;
    const int PACKET_SIZE = 1024;
    const int CONFIGTIMER_INTERVAL = 100;
}

MultipleBurnDlg::MultipleBurnDlg(QWidget *parent)
    : QMainWindow(parent),
      ui(new Ui::MultipleBurn),
      xNum(XNUM_VALUE),
      burnCtrlNum(0),
      saveConfigAction(nullptr),
      checkComAction(nullptr),
      refreshComAction(nullptr),
      checkComTimer(nullptr),
      checkComthread(nullptr),
      chipType(ChipType::WIFI5GNB),
      isAuto(true),
      isReopenCom(false),
      bootType(BOOT_ROM),
      isEraseMode(0),
      isSecConn(false),
      period(PERIOD_VALUE),
      baud(0),
      databits(0),
      stopbits(0),
      parity(QSerialPort::NoParity),
      flowctrl(0),
      forceReadTime(0),
      isResetAfterSuccess(false),
      modemPacketSizeBackup(PACKET_SIZE),
      isSwitchAfterLoader(false),
      isForceReadWithSleep(false),
      connectConfirmSleepTimeout(SLEEP_TIME_OUT),
      connectConfirmWaitTimeout(WAIT_TIME_OUT),
      indenpendent(false),
      strFilePath(""),
      totalTime(0),
      successTime(0),
      failTime(0),
      curWaitTime(0),
      curDoingTime(0),
      curSuccessTime(0),
      curFailTime(0),
      curFinalToWaitTime(0),
      fsm(MultipleBurnDlg::FactionFsm::FACTION_NONE),
      timerConsumed(nullptr),
      isEncrypt(false),
      transmissionMode(0),
      chipModel(0),
      infoStartAddress(0),
      isReadBack(false),
      isRun(false),
      loaderFile(""),
      loaderSize(0),
      parameterFilePath(""),
      eraseBaseNum(0)
{
    qRegisterMetaType<LPVOID>("LPVOID");
    qRegisterMetaType<WPARAM>("WPARAM");
    qRegisterMetaType<LPARAM>("LPARAM");

    vecMultipleBurnDlg.clear();
    checkComthread = new MyThreadClass::MyThread();
    if (checkComthread != nullptr) {
        checkCom.moveToThread(checkComthread);
        checkComthread->start();
        connect(this, &MultipleBurnDlg::SignalPostMessage, &checkCom, &CheckCom::CommWiteThread);
    }
    binInfoArray.clear();
    if (ui == nullptr) {
        return;
    }
    ui->setupUi(this);
    ui->lineEditSuccess->setText(QString::number(successTime));
    ui->lineEditFail->setText(QString::number(failTime));
    ui->lineEditRate->setText("0%");

    QPalette pal = ui->lineEditSuccess->palette();
    pal.setBrush(QPalette::Base, COLOR_RGB_VALUE_GREEN);
    ui->lineEditSuccess->setPalette(pal);
    pal = ui->lineEditFail->palette();
    pal.setBrush(QPalette::Base, COLOR_RGB_VALUE_RED);
    ui->lineEditFail->setPalette(pal);
    this->setWindowModality(Qt::ApplicationModal);
}

MultipleBurnDlg::~MultipleBurnDlg()
{
    if (ui != nullptr) {
        delete ui;
        ui = nullptr;
    }

    for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
        if (vecMultipleBurnDlg[i] != nullptr) {
            delete vecMultipleBurnDlg[i];
            vecMultipleBurnDlg[i] = nullptr;
        }
    }
    vecMultipleBurnDlg.clear();

    if (saveConfigAction != nullptr) {
        delete saveConfigAction;
        saveConfigAction = nullptr;
    }

    if (checkComAction != nullptr) {
        delete checkComAction;
        checkComAction = nullptr;
    }

    if (refreshComAction != nullptr) {
        delete refreshComAction;
        refreshComAction = nullptr;
    }

    if (checkComTimer != nullptr) {
        delete checkComTimer;
        checkComTimer = nullptr;
    }
}

void MultipleBurnDlg::InitUi()
{
    if (ui == nullptr || xNum == 0) {
        return;
    }
    int rowCount = ((burnCtrlNum % xNum) != 0) ? (burnCtrlNum / xNum + 1) : (burnCtrlNum / xNum);
    unsigned int k = 0;
    for (int i = 0; i < rowCount; i++) {
        if (k >= burnCtrlNum) {
            break;
        }
        for (int j = 0; j < xNum; j++) {
            if (k >= burnCtrlNum) {
                break;
            }
            ui->MultipleLayout->addWidget(vecMultipleBurnDlg[k], i, j, 1, 1);
            k++;
        }
    }
    // 菜单栏设置
    saveConfigAction = new QAction(tr("Save config"));
    ui->menuSetting->addAction(saveConfigAction);
    checkComAction = new QAction(tr("Check COM"));
    refreshComAction = new QAction(tr("Refresh COM list"));
    if (saveConfigAction != nullptr) {
        connect(saveConfigAction, &QAction::triggered, this, &MultipleBurnDlg::SlotSaveConfigAction);
    }
    if (checkComAction != nullptr) {
        connect(checkComAction, &QAction::triggered, this, &MultipleBurnDlg::SlotCheckComAction);
    }
    if (refreshComAction != nullptr) {
        connect(refreshComAction, &QAction::triggered, this, &MultipleBurnDlg::SlotRefreshComAction);
    }
    connect(ui->btnConnectAll, &QPushButton::clicked, this, &MultipleBurnDlg::SlotBtnClickedButtonOneKeyConnect);
    connect(ui->btnDisconnectAll, &QPushButton::clicked, this, &MultipleBurnDlg::SlotBnClickedButtonOneKeyDisconnect);
    bool useExactTimer = true;
    for (unsigned int i = 0; i < burnCtrlNum; i++) {
        MultipleBurnDlgForOne *multiple = vecMultipleBurnDlg[i];
        InitMultipleParam(*multiple, useExactTimer);
    }
    if (!Global::IsUSBType(chipType)) {
        RefreshAllComList();
    }
    configTimer = new QTimer(this);
    if (configTimer != nullptr) {
        connect(configTimer, &QTimer::timeout, this, &MultipleBurnDlg::SlotConfigTimerTimeOut);
        configTimer->start(CONFIGTIMER_INTERVAL);
    }
}

void MultipleBurnDlg::SlotSaveConfigAction()
{
    emit SignalSaveDlgConfig();
    QString path = DataConvertor::GetBurnToolConfigPathNew();
    QSettings cfg(path, QSettings::IniFormat);
    for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
        MultipleBurnDlgForOne *item = vecMultipleBurnDlg[i];
        QString key = IDS_STRING_33185 + QString::number(i + 1);
        cfg.setValue("com_disposition/" + key, QString::number(item->GetSelectCom()));
    }

    if (QMessageBox::information(this, stringClass.GetInformation(), stringClass.GetOutPutConfigFile(),
                                 stringClass.GetYes(), stringClass.GetNo()) == 1) {
        return;
    }
    QString filePath = QFileDialog::getSaveFileName(this, tr("Select File"), "", stringClass.GetIdsString33074());
    if (filePath.isEmpty() || path == filePath) {
        return;
    }
    QFile file(filePath);
    if (file.exists()) {
        int ret = QMessageBox::warning(nullptr, "", stringClass.GetIdsString33075(),
                                       stringClass.GetYes(), stringClass.GetNo());
        if (ret == 1) {
            return;
        }
        file.remove();
    }
    file.copy(path, filePath);
}

void MultipleBurnDlg::SlotCheckComAction()
{
    if (checkComTimer == nullptr) {
        checkComTimer = new QTimer();
    }
    for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
        if (vecMultipleBurnDlg[i]->GetBurnFsm() != HI_BURN_FSM::FSM_NONE) {
            QMessageBox::warning(nullptr, "warning", stringClass.GetIdsString32984());
            return;
        }
    }
    emit SignalPostMessage(static_cast<unsigned int>(CheckComWiteThreadMsg::WITE_THREAD_MSG_STARTCHECKCOM), 0, 0);
    if (checkComTimer == nullptr) {
        checkComTimer = new QTimer();
    }
    if (checkComTimer != nullptr) {
        connect(checkComTimer, &QTimer::timeout, this, &MultipleBurnDlg::SlotCheckComTimeOut);
        checkComTimer->start(CHECK_COM_TIME);
    }
}

void MultipleBurnDlg::SlotCheckComTimeOut()
{
    if (checkComTimer == nullptr) {
        return;
    }
    if (!checkCom.IsBusy()) {
        checkComTimer->stop();
        if (QMessageBox::information(nullptr, stringClass.GetInformation(), checkCom.GetStrResult(),
            stringClass.GetOk(), stringClass.GetCancel()) == 1) {
            checkCom.SetApplyResult(false);
            return;
        }
        checkCom.SetApplyResult(true);
        checkCom.SaveResult();
        if (checkCom.IsApplyResult()) {
            LoadConfig();
        }
    }
}

void MultipleBurnDlg::SlotConfigTimerTimeOut()
{
    if (configTimer == nullptr) {
        return;
    }
    configTimer->stop();
    delete configTimer;
    configTimer = nullptr;
    LoadConfig();
}

void MultipleBurnDlg::LoadConfig()
{
    QString path = DataConvertor::GetBurnToolConfigPathNew();
    QFile file(path);
    if (!file.exists()) {
        return;
    }
    QSettings cfg(path, QSettings::IniFormat);
    QStringList groups = cfg.childGroups();
    if (!groups.contains("com_disposition")) {
        return;
    }
    if (QMessageBox::information(nullptr, stringClass.GetInformation(), stringClass.GetIdsString33184(),
                                 stringClass.GetYes(), stringClass.GetNo()) == 1) {
        return;
    }
    QVector<unsigned int> comArray;
    for (unsigned int i = 0; i < EFUSE_ITEM_MAX; ++i) {
        QString strEfuseName = IDS_STRING_33185 + QString::number(1 + i);
        int com = cfg.value("com_disposition/" + strEfuseName).toInt();
        comArray.push_back(com);
    }
    for (int i = 0; i < comArray.size() && i < vecMultipleBurnDlg.size(); i++) {
        QString strtmp = "COM" + QString::number(comArray[i]);
        vecMultipleBurnDlg[i]->FindAndSelectString(strtmp);
    }
}

void MultipleBurnDlg::SlotRefreshComAction() const
{
}

void MultipleBurnDlg::SetCtrlNum(int num)
{
    if (num > 0xffff) {
        return;
    }
    for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
        if (vecMultipleBurnDlg[i] != nullptr) {
            delete vecMultipleBurnDlg[i];
            vecMultipleBurnDlg[i] = nullptr;
        }
    }
    vecMultipleBurnDlg.clear();
    for (int i = 0; i < num; i++) {
        MultipleBurnDlgForOne *multipleBurnDlg = new MultipleBurnDlgForOne();
        if (multipleBurnDlg != nullptr) {
            vecMultipleBurnDlg.push_back(multipleBurnDlg);
            connect(multipleBurnDlg, &MultipleBurnDlgForOne::SignalUpdateList,
                    this, &MultipleBurnDlg::SignalUpdateList);
            connect(multipleBurnDlg, &MultipleBurnDlgForOne::SignalNotifyState,
                    this, &MultipleBurnDlg::SlotNotifyState);
        }
    }
    burnCtrlNum = num;
}

void MultipleBurnDlg::SetOneLineNum(int num)
{
    if (num <= 0) {
        xNum = 10; // default 10
    } else {
        xNum = num;
    }
}

void MultipleBurnDlg::closeEvent(QCloseEvent * event)
{
    SlotBnClickedButtonOneKeyDisconnect();
    emit SignalClose();
    QMainWindow::closeEvent(event);
}

void MultipleBurnDlg::SlotBtnClickedButtonOneKeyConnect()
{
    burnCtrlNum = 0;
    if (Global::IsUSBType(this->chipType)) {
        Global::mMutex.lock();
        Global::mUsbSerialLists.clear();
        Global::mMutex.unlock();
        ui->btnConnectAll->setEnabled(false);
        for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
            if (vecMultipleBurnDlg[i]->ConnectUSBHandle() == ERR_SOP_SUCCESS) {
                burnCtrlNum++;
            }
        }
    } else if (this->chipType == ChipType::MCU) {
        for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
            if (vecMultipleBurnDlg[i]->ConnectMCUHandle() == ERR_SOP_SUCCESS) {
                burnCtrlNum++;
            }
        }
    } else {
        for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
            if (vecMultipleBurnDlg[i]->OnlyConnectHandle() == ERR_SOP_SUCCESS) {
                burnCtrlNum++;
            }
        }
    }
}

void MultipleBurnDlg::RefreshAllComList()
{
    HKEY hKey = nullptr;
    ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,  IDS_STRING_33109.toStdWString().c_str(), 0,
        KEY_READ, &hKey);
    QStringList array;
    DataConvertor::RefreshComList(array);
    for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
        vecMultipleBurnDlg[i]->RefreshAllComList(array, i);
    }
}

void MultipleBurnDlg::InitMultipleParam(MultipleBurnDlgForOne &multiple, bool useExactTimer)
{
    multiple.SetChipType(chipType);
    multiple.SetBootType(bootType);
    multiple.SetAutoBurnFlag(isAuto);
    multiple.SetReopenComFlag(isReopenCom);
    multiple.SetPeriod(period);
    multiple.SetInfoArray(strFilePath);
    multiple.SetInfoArray(binInfoArray);
    multiple.SetSecConn(isSecConn);
    multiple.SetEraseAll(isEraseMode);
    multiple.UpdateComSetting(baud, databits, stopbits, parity, flowctrl);
    multiple.SetForceReadFlag(isForceReadWithSleep);
    multiple.SetForceReadTime(forceReadTime);
    multiple.SetIsResetAfterSuccess(isResetAfterSuccess);
    multiple.SetYModemEachPackageSize(modemPacketSizeBackup);
    multiple.SetIsSwitchAfterLoader(isSwitchAfterLoader);
    multiple.SetConfirmConnectSleepTime(connectConfirmSleepTimeout);
    multiple.SetConfirmConnectWaitTime(connectConfirmWaitTimeout);
    multiple.SetResultByOwnerFlag(true);
    multiple.SetBurnTimeout(0xffffffff); // timeout 6000000
    multiple.SetUseExactTimer(useExactTimer);
    multiple.SetIndenpendentBurn(indenpendent);
    multiple.SetIsEncrypt(isEncrypt);
    multiple.SetEncryptBuffer(encryptBuffer);
    multiple.SetUsbDeviceInfo(deviceInfo);
    multiple.SetChipModel(chipModel);
    multiple.SetMcuConfig(mcuConfig);
    multiple.SetJtagSwd(jtagSwd);
    multiple.SetTransmissionMode(transmissionMode);
    multiple.SetChipId(chipId);
    multiple.SetInfoStartAddress(infoStartAddress);
    multiple.SetMainStartAddress(mainStartAddrInfo);
    multiple.SetSramAddrInfo(sramAddrInfo);
    multiple.SetIsReadBack(isReadBack);
    multiple.SetIsRun(isRun);
    multiple.SetLoaderInfo(loaderFile, loaderSize);
    multiple.SetParameterSaveInfo(parameterFilePath, eraseBaseNum);
    multiple.InitAllConfig();
}

void MultipleBurnDlg::SetChipType(ChipType chipTypeNeedSet)
{
    if (ui == nullptr) {
        return;
    }
    this->chipType = chipTypeNeedSet;
    if (chipTypeNeedSet == ChipType::SPARTA || chipTypeNeedSet == ChipType::MELODY ||
        chipTypeNeedSet == ChipType::COMBS25 || chipTypeNeedSet == ChipType::MCU) {
        ui->lineEditTime->hide();
    }
}

void MultipleBurnDlg::SetChipModel(int chipModelNeedSet)
{
    this->chipModel = chipModelNeedSet;
}

void MultipleBurnDlg::SetAutoBurnFlag()
{
    this->isAuto = true;
}

void MultipleBurnDlg::SetReopenComFlag(bool reopenComFlag)
{
    this->isReopenCom = reopenComFlag;
}

void MultipleBurnDlg::SetBootType(BootType type)
{
    this->bootType = type;
}

void MultipleBurnDlg::SetEraseAll(int eraseMode)
{
    this->isEraseMode = eraseMode;
}

void MultipleBurnDlg::SetSecConn(bool isSecConnNeedSet)
{
    this->isSecConn = isSecConnNeedSet;
}

void MultipleBurnDlg::SetPeriod(int periodNeedSet)
{
    this->period = periodNeedSet;
}

void MultipleBurnDlg::SetMcuConfig(McuConfig config)
{
    this->mcuConfig = config;
}

void MultipleBurnDlg::SetJtagSwd(McuJtagSwd config)
{
    this->jtagSwd = config;
}

void MultipleBurnDlg::SetTransmissionMode(int tarns)
{
    this->transmissionMode = tarns;
}

void MultipleBurnDlg::SetChipId(McuChipId id)
{
    this->chipId = id;
}


void MultipleBurnDlg::UpdateComSetting(UINT baudNeedUpdate, UINT databitsNeedUpdate, UINT stopbitsNeedUpdate,
                                       QSerialPort::Parity parityNeedUpdate, UINT flowctrlNeedUpdate)
{
    this->baud = baudNeedUpdate;
    this->databits = databitsNeedUpdate;
    this->stopbits = stopbitsNeedUpdate;
    this->parity = parityNeedUpdate;
    this->flowctrl = flowctrlNeedUpdate;
}

void MultipleBurnDlg::SetForceReadTime(UINT forceReadTimeNeedSet)
{
    this->forceReadTime = forceReadTimeNeedSet;
}

void MultipleBurnDlg::SetIsResetAfterSuccess(bool isResetAfterSuccessNeedSet)
{
    this->isResetAfterSuccess = isResetAfterSuccessNeedSet;
}

void MultipleBurnDlg::SetYModemEachPackageSize(unsigned int modemPacketSizeBackupNeedSet)
{
    this->modemPacketSizeBackup = modemPacketSizeBackupNeedSet;
}

void MultipleBurnDlg::SetIsSwitchAfterLoader(bool isSwitchAfterLoaderNeedSet)
{
    this->isSwitchAfterLoader = isSwitchAfterLoaderNeedSet;
}

void MultipleBurnDlg::SetInfoArray(const QMap<int, BIN_INFO> &infoArray)
{
    this->binInfoArray = infoArray;
}

void MultipleBurnDlg::SetInfoArray(const QString &filePath)
{
    this->strFilePath = filePath;
}

void MultipleBurnDlg::SetForceReadFlag(bool isForceRead)
{
    this->isForceReadWithSleep = isForceRead;
}

void MultipleBurnDlg::SetConfirmConnectSleepTime(UINT time)
{
    this->connectConfirmSleepTimeout = time;
}

void MultipleBurnDlg::SetConfirmConnectWaitTime(UINT time)
{
    this->connectConfirmWaitTimeout = time;
}

void MultipleBurnDlg::SetIndenpendentBurn(bool indenpendentNeedSet)
{
    this->indenpendent = indenpendentNeedSet;
}

void MultipleBurnDlg::SetIsEncrypt(bool isEncryptNeedSet)
{
    this->isEncrypt = isEncryptNeedSet;
}

void MultipleBurnDlg::SetEncryptBuffer(ENCRYPT_BUFFER encryptBufferNeedSet)
{
    this->encryptBuffer = encryptBufferNeedSet;
}

void MultipleBurnDlg::SetUsbDeviceInfo(HidDeviceInfo usbDeviceInfo)
{
    this->deviceInfo = usbDeviceInfo;
}

void MultipleBurnDlg::SetUsbLocations(QStringList usbLocations)
{
    for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
        vecMultipleBurnDlg[i]->RefreshAllComList(usbLocations, i);
    }
}

void MultipleBurnDlg::SetInfoStartAddress(ulong startAddr)
{
    this->infoStartAddress = startAddr;
}

void MultipleBurnDlg::SetMainStartAddress(MainStartAddrInfo startAddrInfo)
{
    this->mainStartAddrInfo = startAddrInfo;
}

void MultipleBurnDlg::SetSramAddrInfo(SramAddrInfo sainfo)
{
    this->sramAddrInfo = sainfo;
}

void MultipleBurnDlg::SetIsReadBack(bool readBack)
{
    this->isReadBack = readBack;
}

void MultipleBurnDlg::SetIsRun(bool run)
{
    this->isRun = run;
}

void MultipleBurnDlg::SetLoaderInfo(QString loaderFileNeedSet, int loaderSizeNeedSet)
{
    this->loaderFile = loaderFileNeedSet;
    this->loaderSize = loaderSizeNeedSet;
}

void MultipleBurnDlg::SetParameterSaveInfo(const QString &filePath, ulong baseNum)
{
    this->parameterFilePath = filePath;
    this->eraseBaseNum = baseNum;
}

void MultipleBurnDlg::SlotNotifyState(unsigned int ret, unsigned int progress)
{
    if (ui == nullptr) {
        return;
    }
    if (indenpendent && ret == NOTIFY_TYPE_RESULT) {
        if (progress == 0) {
            totalTime++;
            successTime++;
        } else if (progress == ERR_DOING) {
        } else if (progress == ERR_WAITING) {
        } else {
            totalTime++;
            failTime++;
        }
        ui->lineEditSuccess->setText(QString::number(successTime));
        ui->lineEditFail->setText(QString::number(failTime));
        if (totalTime > 0) {
            ui->lineEditRate->setText(QString::number(static_cast<float>(successTime) / \
                                                      static_cast<float>(totalTime) * NUM_ONE_HUNDRED) + "%");
        }
    } else if (ret == NOTIFY_TYPE_RESULT) {
        switch (fsm) {
            case MultipleBurnDlg::FactionFsm::FACTION_NONE:
                HandleFsmNone(progress);
                break;
            case MultipleBurnDlg::FactionFsm::FACTION_WAITING:
                HandleFsmWaiting(progress);
                break;
            case MultipleBurnDlg::FactionFsm::FACTION_DOING:
                HandleFsmDoing(progress);
                break;
            case MultipleBurnDlg::FactionFsm::FACTION_FINAL:
                HandleFsmFinal(progress);
                break;
            default:
                break;
        }
        ui->lineEditSuccess->setText(QString::number(successTime));
        ui->lineEditFail->setText(QString::number(failTime));
        if (totalTime > 0) {
            ui->lineEditRate->setText(QString::number(static_cast<float>(successTime) / \
                                                      static_cast<float>(totalTime) * NUM_ONE_HUNDRED)  + "%");
        }
    }
}

void MultipleBurnDlg::HandleFsmNone(LPARAM lParam)
{
    if (lParam == ERR_WAITING) {
        curWaitTime++;
    }
    if (curWaitTime >= burnCtrlNum) {
        fsm = MultipleBurnDlg::FactionFsm::FACTION_WAITING;
        for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
            vecMultipleBurnDlg[i]->ShowResult();
        }
    }
}

void MultipleBurnDlg::HandleFsmWaiting(LPARAM lParam)
{
    if (lParam == ERR_DOING) {
        TimerConsumedStart();
        startTime.GetHostDateTime();
        fsm = MultipleBurnDlg::FactionFsm::FACTION_DOING;
        curDoingTime++;
    }
    if (lParam == ERR_WAITING) {
        curWaitTime++;
    }

    if (!Global::IsUSBType(this->chipType)) {
        if (lParam != ERR_WAITING && lParam != ERR_DOING && lParam != 0) {
            totalTime++;
            failTime++;
        }
    } else {
        if (lParam != ERR_WAITING && lParam != ERR_DOING && lParam != 0 && lParam != ERR_USB_IOERR) {
            totalTime++;
            failTime++;
        }
    }
}

void MultipleBurnDlg::SlotConsumedTimeOut()
{
    if (ui == nullptr) {
        return;
    }
    QString strTimeConsume;
    QString strTime;
    RMDA_TIME_STRU currtUpgTime;
    currtUpgTime.GetHostDateTime();
    S64 sllMilliDelta = currtUpgTime.GetValMilliSec() - startTime.GetValMilliSec();
    RMDA_TIME_STRU stTimeDelta;
    stTimeDelta.SetValMilliSec(sllMilliDelta);
    strTime = stTimeDelta.FormatDayTimeToColonStr(FALSE);
    strTimeConsume = strTime;
    ui->lineEditTime->setText(strTimeConsume);
}

void MultipleBurnDlg::HandleFsmDoing(LPARAM lParam)
{
    if (lParam == 0) {
        totalTime++;
        successTime++;
        curSuccessTime++;
        fsm = MultipleBurnDlg::FactionFsm::FACTION_FINAL;
        if (JudgeBurnFail()) {
            TimerConsumedStop();
            for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
                vecMultipleBurnDlg[i]->SetResultFromAToB(ERR_WAITING, ERR_TIMEOUT_WAIT_HISILICON);
            }
        } else if (JudgeFinish()) {
            TimerConsumedStop();
            Global::mMutex.lock();
            Global::mUsbSerialLists.clear();
            Global::mMutex.unlock();
        }
    } else if (lParam == ERR_DOING) {
        curDoingTime++;
    } else if (lParam == ERR_WAITING) {
    } else if (lParam == ERR_USB_IOERR) {
    } else {
        totalTime++;
        failTime++;
        curFailTime++;
        fsm = MultipleBurnDlg::FactionFsm::FACTION_FINAL;
        if (JudgeBurnFail()) {
            TimerConsumedStop();
            for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
                vecMultipleBurnDlg[i]->SetResultFromAToB(ERR_WAITING, ERR_TIMEOUT_WAIT_HISILICON);
            }
        }
    }
}

bool MultipleBurnDlg::JudgeBurnFail() const
{
    if (curWaitTime > curDoingTime && (curSuccessTime > 0) &&
        (curSuccessTime + curFailTime >= curDoingTime)) {
        return true;
    }
    return false;
}

bool MultipleBurnDlg::JudgeFinish() const
{
    if (curSuccessTime + curFailTime >= curDoingTime) {
        return true;
    }
    return false;
}

void MultipleBurnDlg::HandleFsmFinal(LPARAM lParam)
{
    if (lParam == ERR_DOING) {
        TimerConsumedStart();
        startTime.GetHostDateTime();
        fsm = MultipleBurnDlg::FactionFsm::FACTION_DOING;
        curDoingTime++;
    } else if (lParam == ERR_WAITING) {
        curFinalToWaitTime++;
        HandleFsmFinalSplitCode();
    } else if (lParam == ERR_USB_IOERR) {
    } else {
        totalTime++;
        if (lParam == 0) {
            successTime++;
            curSuccessTime++;
        } else {
            failTime++;
            curFailTime++;
        }
        if (JudgeBurnFail()) {
            TimerConsumedStop();
            for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
                vecMultipleBurnDlg[i]->SetResultFromAToB(ERR_WAITING, ERR_TIMEOUT_WAIT_HISILICON);
            }
        } else if (JudgeFinish()) {
            TimerConsumedStop();
            Global::mMutex.lock();
            Global::mUsbSerialLists.clear();
            Global::mMutex.unlock();
        }
    }
}

void MultipleBurnDlg::TimerConsumedStart()
{
    if (timerConsumed == nullptr) {
        timerConsumed = new QTimer();
    }
    if (timerConsumed != nullptr) {
        timerConsumed->setInterval(TIMER_CONSUMED_INTERVAL);
        timerConsumed->setTimerType(Qt::PreciseTimer);
        timerConsumed->start();
        connect(timerConsumed, &QTimer::timeout, this, &MultipleBurnDlg::SlotConsumedTimeOut);
    }
}

void MultipleBurnDlg::TimerConsumedStop()
{
    if (timerConsumed != nullptr) {
        timerConsumed->stop();
        delete timerConsumed;
        timerConsumed = nullptr;
    }
}

void MultipleBurnDlg::HandleFsmFinalSplitCode()
{
    if (!JudgeGoToWaiting()) {
        return;
    }

    curWaitTime = 0;
    curSuccessTime = 0;
    curFailTime = 0;
    curDoingTime = 0;
    curFinalToWaitTime = 0;
    fsm = MultipleBurnDlg::FactionFsm::FACTION_WAITING;
    for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
        unsigned int result = vecMultipleBurnDlg[i]->GetResult();
        if (result == 0 || result > ERR_FAILURE) {
            vecMultipleBurnDlg[i]->SetResult(ERR_WAITING);
            vecMultipleBurnDlg[i]->ShowResult();
        } else {
            vecMultipleBurnDlg[i]->SetResult(ERR_WAITING);
        }
    }
}

bool MultipleBurnDlg::JudgeGoToWaiting() const
{
    if (curSuccessTime == curFinalToWaitTime && curSuccessTime + curFailTime >= curWaitTime) {
        return TRUE;
    }
    return FALSE;
}

void MultipleBurnDlg::SlotBnClickedButtonOneKeyDisconnect()
{
    ui->btnConnectAll->setEnabled(true);
    for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
        vecMultipleBurnDlg[i]->KillAllTimer();
        vecMultipleBurnDlg[i]->SetShutDown();
    }

    if (this->chipType == ChipType::MCU) {
        for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
            vecMultipleBurnDlg[i]->DisconnectMCUHandle();
        }
    } else if (this->chipType == ChipType::USB4GCAT1 || chipType == ChipType::USBHI3322) {
        for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
            vecMultipleBurnDlg[i]->DisconnectUSBHandle();
        }
    } else {
        for (int i = 0; i < vecMultipleBurnDlg.size(); i++) {
            vecMultipleBurnDlg[i]->OnlyDisconnectHandle();
        }
    }

    curWaitTime = 0;
    curSuccessTime = 0;
    curFailTime = 0;
    curDoingTime = 0;
    curFinalToWaitTime = 0;
    fsm = MultipleBurnDlg::FactionFsm::FACTION_NONE;

    successTime = 0;
    failTime = 0;
    totalTime = 0;

    ui->lineEditTime->clear();
    ui->lineEditSuccess->setText(QString::number(successTime));
    ui->lineEditFail->setText(QString::number(failTime));
    ui->lineEditRate->setText("0%");
    TimerConsumedStop();
}

}
